#pragma once

#include <stdint.h>
#include <string>
#include <functional>
#include <type_traits>

namespace cast_helper
{

	template<typename ret_t, typename param_t, 
		std::enable_if_t<std::is_convertible_v <std::decay_t<ret_t>, std::decay_t<param_t>>, int> = 0>
	ret_t do_cast(param_t&& param) {
		return static_cast<ret_t>(param);
	}

	template<typename ret_t, typename param_t, std::enable_if_t<std::is_integral_v<std::decay_t<ret_t>>, int> = 0,
		std::enable_if_t<std::is_convertible_v <const char*, std::decay_t<param_t>>, int> = 0>
	ret_t do_cast(param_t&& param) {
		return static_cast<ret_t>(std::stoll(param));
	}

	template<typename ret_t, typename param_t, std::enable_if_t<std::_Is_any_of_v<std::decay_t<ret_t>, float, double>, int> = 0,
		std::enable_if_t<std::is_convertible_v <const char*, std::decay_t<param_t>>, int> = 0>
	ret_t do_cast(param_t&& param) {
		return static_cast<ret_t>(std::stod(param));
	}

	template<typename ret_t, typename param_t, std::enable_if_t<std::is_same_v<std::decay_t<ret_t>, long double>, int> = 0,
		std::enable_if_t<std::is_convertible_v <const char*, std::decay_t<param_t>>, int> = 0>
	ret_t do_cast(param_t&& param) {
		return static_cast<ret_t>(std::stold(param));
	}

	template<typename ret_t, typename param_t, std::enable_if_t<std::is_same_v<std::decay_t<ret_t>, std::string>, int> = 0>
	ret_t do_cast(param_t&& param) {
		return std::to_string(param);
	}
}

template<typename ret_t, typename param_t>
ret_t type_cast(param_t&& parm)
{
	return cast_helper::do_cast<ret_t, param_t>(std::forward<param_t>(parm));
}

